﻿//========================================================= 
/**@file LC_CipherCmdDriver.h
 * @brief 通信加密传输驱动
 * 
 * @date 2017-10-20   20:03:59
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_LC_CIPHERCMDDRIVER_H_
#define _LIBZHOUYB_LC_CIPHERCMDDRIVER_H_
//--------------------------------------------------------- 
#include "../CommonCmdDriver.h"

#include "../../lc/inc/LC_EncryptCmdAdapter.h"
using zhou_yb::application::lc::LC_EncryptCmdAdapter;

#include "../../../extension/security/security.h"
using zhou_yb::extension::security::ISecurityAlgorithm;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
//--------------------------------------------------------- 
/// 加密器工厂接口
typedef IFactory<Ref<ISecurityAlgorithm> > ICipherFactory;
//--------------------------------------------------------- 
/// 随机产生密钥序号用于通信加密
class LC_RandomEncryptCmdAdapter : public LC_EncryptCmdAdapter
{
protected:
    byte _modeMin;
    byte _modeMax;

    static byte _RangeMode(byte mMin, byte mMax)
    {
        uint tick = Timer::TimeTick();
        srand(tick);
        int r = rand();
        int offset = mMax - mMin;
        return mMin + (r % offset);
    }
public:
    LC_RandomEncryptCmdAdapter() : LC_EncryptCmdAdapter()
    {
        _modeMin = 0;
        _modeMax = 0;
    }
    inline byte RandomMode()
    {
        byte mode = EncMode;
        if(_modeMin < _modeMax)
        {
            mode = _RangeMode(_modeMin, _modeMax);
        }
        return mode;
    }
    virtual bool Write(const ByteArray& data)
    {
        /*
        if(_modeMin < _modeMax)
        {
            EncMode = _RangeMode(_modeMin, _modeMax);
        }
        */
        ++EncMode;
        if(EncMode > 0x0F)
            EncMode = 1;
        return LC_EncryptCmdAdapter::Write(data);
    }
    void RangeMode(byte mMin, byte mMax)
    {
        if(mMax == mMin)
        {
            EncMode = mMin;
            _modeMax = mMax;
            _modeMin = mMin;
            return;
        }
        if(mMax < mMin)
        {
            _modeMax = mMin;
            _modeMin = mMax;
            return;
        }
        
        _modeMax = mMax;
        _modeMin = mMin;
    }
};
//--------------------------------------------------------- 
/**
 * @brief 通信加密驱动
 * @date 2017-10-20 20:05
 */
class LC_CipherCmdDriver : public CommonCmdDriver
{
protected:
    Ref<ICipherFactory> _cipher;
    Ref<IInteractiveTrans> _activeTrans;
    LC_RandomEncryptCmdAdapter _cmdAdapter;

    bool _FactoryCreate(byte mode)
    {
        Ref<ISecurityAlgorithm> obj;
        string key = ArgConvert::ToString(mode);
        if(!_cipher->Create(obj, key.c_str()))
            return false;
        _cmdAdapter.Cipcher.Put(mode, obj);
        return true;
    }
    void _FactoryDispose()
    {
        LC_EncryptCmdAdapter::EnumeratorType enumer = _cmdAdapter.Cipcher.GetEnumerator();
        while(enumer.MoveNext())
        {
            _cipher->Dispose(enumer.Current().Value);
        }
        _cmdAdapter.Cipcher.Clear();
    }
    bool _CreateMode(IStringArguments& arg, IStringArguments& rlt, const char* sKey, byte& mode)
    {
        rlt.Put(sKey, ArgConvert::ToString(mode));
        string sMode;
        if(arg.Get(sKey, sMode))
        {
            mode = ArgConvert::FromString<byte>(sMode);
            return _FactoryCreate(mode);
        }
        return true;
    }
public:
    //----------------------------------------------------- 
    LC_CipherCmdDriver() : CommonCmdDriver()
    {
        _errGetter.Add(_cmdAdapter);
        _logSetter.select(_cmdAdapter);

        _activeTrans = _cmdAdapter;

        _RegisteCMD(LC_CipherCmdDriver, UpdateCipher);
        _RegisteCMD(LC_CipherCmdDriver, RangeMode);
        _RegisteCMD(LC_CipherCmdDriver, Ack);
        _RegisteCMD(LC_CipherCmdDriver, Clean);
        _RegisteCMD(LC_CipherCmdDriver, PackCMD);
        _RegisteCMD(LC_CipherCmdDriver, UnpackCMD);
        _RegisteCMD(LC_CipherCmdDriver, IsFormattedCMD);
        _RegisteCMD(LC_CipherCmdDriver, IsCipherMode);
        _RegisteCMD(LC_CipherCmdDriver, AckWrite);
        _RegisteCMD(LC_CipherCmdDriver, AckRead);
        
        _RegisteExceptCMD(LC_CipherCmdDriver);
        _RegisteIInteractiveTransCMD(LC_CipherCmdDriver);
        _RegisteInterfaceCMD(LC_CipherCmdDriver, IInteractiveTrans);
        _RegisteAdapterCMD(LC_CipherCmdDriver);
    }
    LC_CMD_INTERFACE_GETTER(IInteractiveTrans, _activeTrans);
    LC_CMD_INTERACTIVETRANS(_activeTrans);
    LC_CMD_METHOD(AckWrite)
    {
        bool bOK = Write(arg, rlt);
        if(bOK)
        {
            ByteBuilder buff(16);
            ByteConvert::ToAscii(_cmdAdapter.Ack, buff);
            rlt.Put("ACK", buff.GetString());
        }
        return bOK;
    }
    LC_CMD_METHOD(AckRead)
    {
        bool bOK = Read(arg, rlt);
        if(bOK)
        {
            rlt.Put("Mode", ArgConvert::ToString(_cmdAdapter.Mode()));
        }
        return bOK;
    }
    LC_CMD_ADAPTER(IInteractiveTrans, _cmdAdapter);
    LC_CMD_EXCEPT()
    {
        EXCEPT_CMD(UpdateCipher);
        EXCEPT_CMD(RangeMode);
        EXCEPT_CMD(Ack);
        EXCEPT_CMD(Clean);
        EXCEPT_CMD(PackCMD);
        EXCEPT_CMD(UnpackCMD);
        EXCEPT_CMD(IsFormattedCMD);
        return true;
    }
    //----------------------------------------------------- 
    /**
     * @brief 返回指令是否是符合合适的数据
     * @date 2017-11-21 12:08
     * 
     * @param [in] DATA : hex 数据
     * 
     * @retval IsOK : bool 是否为符合格式的数据
     * @retval Length : size_t 缓存的数据长度
     */
    LC_CMD_METHOD(IsFormattedCMD)
    {
        string sData = arg["DATA"].To<string>();
        ByteBuilder data(8);
        DevCommand::FromAscii(sData.c_str(), data);
        size_t len = 0;
        bool bOK = LC_EncryptCmdAdapter::IsFormatted(data, &len);
        rlt.Put("IsOK", ArgConvert::ToString(bOK));
        rlt.Put("Length", ArgConvert::ToString(len));
        return true;
    }
    /**
     * @brief 拼装密文数据
     * @date 2017-11-20 15:41
     *
     * @param DATA : hex 需要发送的数据
     * @param Mode : byte [default:Null] 需要使用的加密模式
     *
     * @retval DATA : 加密后的密文数据
     */
    LC_CMD_METHOD(PackCMD)
    {
        byte mode = arg["Mode"].To<byte>(_cmdAdapter.RandomMode());
        string sData = arg["DATA"].To<string>();
        ByteBuilder data(16);
        ByteBuilder buff(16);
        DevCommand::FromAscii(sData.c_str(), data);
        bool bOK = _cmdAdapter.PackCMD(mode, data, buff);
        if(bOK)
        {
            rlt.Put("DATA", ArgConvert::ToString(buff));
        }
        return bOK;
    }
    /**
     * @brief 解包密文数据
     * @date 2017-11-20 15:41
     *
     * @param DATA : hex 需要解密的数据
     *
     * @retval Mode : byte 数据的通信模式
     * @retval DATA : hex 解密后的明文数据
     * @retval LRC : hex 密钥计算的LRC
     */
    LC_CMD_METHOD(UnpackCMD)
    {
        string sData = arg["DATA"].To<string>();
        ByteBuilder data(16);
        ByteBuilder buff(16);
        ByteBuilder lrc(8);
        DevCommand::FromAscii(sData.c_str(), data);
        byte mode = 0x00;
        bool bOK = _cmdAdapter.UnpackCMD(data, mode, buff, &lrc);
        if(bOK)
        {
            rlt.Put("Mode", ArgConvert::ToString(mode));
            rlt.Put("DATA", ArgConvert::ToString(buff));
            rlt.Put("LRC", ArgConvert::ToString(lrc));
        }
        return bOK;
    }
    /**
     * @brief 是否为加密通道模式
     * @date 2017-12-11 22:10
     *
     * @param [in] Send : hex 需要用于校验通讯的指令
     *
     * @retval IsCipherMode : bool 是否为通信加密模式
     */
    LC_CMD_METHOD(IsCipherMode)
    {
        string sCmd = arg["Send"].To<string>();
        ByteBuilder cmd(8);
        DevCommand::FromAscii(sCmd.c_str(), cmd);
        bool bOK = _cmdAdapter.Write(cmd);
        if(!bOK)
        {
            // 发数据失败
            if(!_cmdAdapter.ActiveDevice()->Write(cmd))
                return false;
        }
        rlt.Put("IsCipherMode", ArgConvert::ToString(bOK));
        return true;
    }
    //----------------------------------------------------- 
    /**
     * @brief 设置通讯密码器和通讯密钥
     * @date 2017-10-20 22:15
     *
     * @param [in] ICipherFactory : Ref<ICipherFactory> [default:Null] 加密器工厂
     * @param [in] Mode : byte [default:Null] 加密模式
     * @param [in] AckMode : byte [default:Null] ACK包的加密模式
     * @param [in] ACK : hex [default:Null] 需要回应的ACK数据
     * @param [in] LrcSize : byte [default:Null] 需要设置的LRC校验包大小
     *
     * @retval Mode : byte 上次的加密模式
     * @retval AckMode : byte 上次的ACK加密模式
     * @retval ACK : hex 上次设置的回应ACK包内容
     * @retval LrcSize : size_t 上次设置的LRC校验包长度
     */
    LC_CMD_METHOD(UpdateCipher)
    {
        Ref<ICipherFactory> cipher = CommandReflectArg(ICipherFactory, arg);
        if(!cipher.IsNull())
        {
            _cipher = cipher;
        }
        _FactoryDispose();

        rlt.Put("ACK", ArgConvert::ToString(_cmdAdapter.Ack));
        rlt.Put("LrcSize", ArgConvert::ToString(_cmdAdapter.LrcSize));

        ASSERT_FuncErrInfo(_CreateMode(arg, rlt, "Mode", _cmdAdapter.EncMode),
            DeviceError::DevInitErr, "创建通信密钥器失败");
        ASSERT_FuncErrInfo(_CreateMode(arg, rlt, "AckMode", _cmdAdapter.AckMode),
            DeviceError::DevInitErr, "创建ACK密钥器失败");

        string sAck;
        if(arg.Get("ACK", sAck))
        {
            _cmdAdapter.Ack.Clear();
            DevCommand::FromAscii(sAck.c_str(), _cmdAdapter.Ack);
        }
        string sLrc;
        if(arg.Get("LrcSize", sLrc))
        {
            _cmdAdapter.LrcSize = ArgConvert::FromString<byte>(sLrc);
        }
        return true;
    }
    /**
     * @brief 设定通信加密的随机密钥范围
     * @date 2017-10-25 22:33
     * 
     * @param [in] Mode : byte 需要固定设置的模式
     * @param [in] AckMode : byte [default:Null] 需要设置的ACK包加密模式
     *
     * @param [in] MIN : byte [default:0x00] 最小随机范围
     * @param [in] MAX : byte [default:0xFF] 最大随机范围
     */
    LC_CMD_METHOD(RangeMode)
    {
        ASSERT_FuncErrInfo(_CreateMode(arg, rlt, "AckMode", _cmdAdapter.AckMode),
            DeviceError::DevInitErr, "创建ACK密钥器失败");

        byte mMin = 0x00;
        byte mMax = 0x00;

        string sMode;
        if(arg.Get("Mode", sMode))
        {
            byte mode = ArgConvert::FromString<byte>(sMode);
            mMin = mode;
            mMax = mode;
        }
        else
        {
            mMin = arg["MIN"].To<byte>(0x00);
            mMax = arg["MAX"].To<byte>(0xFF);
        }
        _cmdAdapter.RangeMode(mMin, mMax);
        for(byte i = mMin;i <= mMax; ++i)
        {
            if(!_FactoryCreate(i))
            {
                string errMsg = "创建通信密钥器[";
                errMsg += _hex(i);
                errMsg += "]失败";
                _logErr(DeviceError::DevInitErr, errMsg.c_str());
                return false;
            }
        }
        return true;
    }
    /**
     * @brief 获取ACK回应包属性
     * @date 2017-10-20 22:29
     * 
     * @retval ACK : hex 上次接收到的ACK
     * @retval Mode : byte 上次接收到的模式
     * @retval LrcSize : byte 上次设置的校验包大小
     */
    LC_CMD_METHOD(Ack)
    {
        ByteBuilder buff(8);
        ByteConvert::ToAscii(_cmdAdapter.Ack, buff);
        rlt.Put("ACK", buff.GetString());
        rlt.Put("Mode", ArgConvert::ToString(_cmdAdapter.Mode()));
        rlt.Put("LrcSize", ArgConvert::ToString(_cmdAdapter.LrcSize));
        return true;
    }
    /**
     * @brief 清除缓存的通信数据
     * @date 2017-10-20 22:33
     */
    LC_CMD_METHOD(Clean)
    {
        _cmdAdapter.Clean();
        return true;
    }
    //----------------------------------------------------- 
};
//--------------------------------------------------------- 
} // nemespace driver
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_LC_CIPHERCMDDRIVER_H_
//========================================================= 